/**
 * ...
 * @author Rob Dravenstott
 * 
 * Primary application code to load images and create main weather display
 * 
 */

import org.as2lib.env.reflect.Delegate; 
import net.produxion.util.XML2Object;

class Ted 
{
	private var _app_root:MovieClip;
	private var _savenewsettingsFunc:Function;
	private var _cp_ref:TedConfig = null;
	
	// Can't find a way to determine original swf doc size, so just default
	private var _original_doc_width:Number = 800;
	private var _original_doc_height:Number = 600;
	
	// Set these thresholds for maximum photo dimensions to retrieve
	private var _x_scale_factor:Number = 1;
	private var _y_scale_factor:Number = 1;	

	private var _httpStatusType:String;
	private var _myxml:XML;
	private var _ted_address:String = "192.168.1.44";  // Default address for ted 5000
	private var _refresh_time:Number = 2000;  // Set refresh time to 2,000 ms
	private var _myTimer:Number = null;
	
	private var _powerNow:Number = 0;
	private var _powerAvg:Number = 0;
	private var _minTdy:Number = 0;
	private var _minTdyHour:Number = 0;
	private var _minTdyMin:Number = 0;
	private var _peakTdy:Number = 0;
	private var _peakTdyHour:Number = 0;
	private var _peakTdyMin:Number = 0;
	private var _minMTD:Number = 0;
	private var _minMTDMonth:Number = 0;
	private var _minMTDDay:Number = 0;
	private var _peakMTD:Number = 0;
	private var _peakMTDMonth:Number = 0; 
	private var _peakMTDDay:Number = 0;
	
	// Initial function to get this started
	public function run (app_root:MovieClip, settings:Object, saveNewSettings:Function):Void
	{
		_app_root = app_root;
		_savenewsettingsFunc = saveNewSettings;
		if (settings.ted_address != undefined)
			_ted_address = String(settings.ted_address);
		if (settings.refresh_time != undefined)
			_refresh_time = Number(settings.refresh_time);

		// Show initial display with zeros
		updateDisplay(); 
		
		var L:Object = new Object();
		L.onResize = Delegate.create(this, this.updateDisplay);
		Stage.addListener(L);

		// Try to get initial data
		this.getTedXML();
	}

	// Make request for Ted 5000 xml data
	private function getTedXML ():Void 
	{
		stopTimer();
		
		_myxml = new XML();
		_myxml.ignoreWhite = true;

		_myxml.onHTTPStatus = Delegate.create(this, this.getHTTPStatus);
		
		_myxml.onLoad = Delegate.create(this, this.parseTedXML);
		
		// Get XML file with list of images
		
		var xml_url:String = "http://" + _ted_address + "/api/LiveData.xml";
		trace("Loading: " + xml_url);
		_myxml.load(xml_url);
	}
	
	// Process xml returned from ted 5000
	private function parseTedXML (success:Boolean):Void 
	{
		// Check if we were successful loading
		if (!success) 
		{
			showTextMessage("Connection error: " + _httpStatusType, 24);
			trace("XML Connection error: "+_httpStatusType+" to: "+_ted_address);
		}
		else
		{
		
			// Create an XML object and populate it
			var contentObj:Object;
			contentObj = XML2Object.deserialize( this._myxml );
			
			delete this._myxml;
			
			_powerNow = Number(contentObj.LiveData.Power.Total.PowerNow.data);
			_powerAvg = Number(contentObj.LiveData.Power.Total.PowerAvg.data);
			_minTdy = Number(contentObj.LiveData.Power.Total.MinTdy.data);
			_minTdyHour = Number(contentObj.LiveData.Power.Total.MinTdyHour.data);
			_minTdyMin = Number(contentObj.LiveData.Power.Total.MinTdyMin.data);
			_peakTdy = Number(contentObj.LiveData.Power.Total.PeakTdy.data);
			_peakTdyHour = Number(contentObj.LiveData.Power.Total.PeakTdyHour.data);
			_peakTdyMin = Number(contentObj.LiveData.Power.Total.PeakTdyMin.data);
			_minMTD = Number(contentObj.LiveData.Power.Total.MinMTD.data);
			_minMTDMonth = Number(contentObj.LiveData.Power.Total.MinMTDMonth.data);
			_minMTDDay = Number(contentObj.LiveData.Power.Total.MinMTDDay.data);
			_peakMTD = Number(contentObj.LiveData.Power.Total.PeakMTD.data);
			_peakMTDMonth = Number(contentObj.LiveData.Power.Total.PeakMTDMonth.data);
			_peakMTDDay = Number(contentObj.LiveData.Power.Total.PeakMTDDay.data);

			trace ("POWERNow: " + _powerNow);
			
			// Refresh Display
			updateDisplay();
		}
		
		//restart Timer
		startTimer(_refresh_time);
	}

	public function updateDisplay():Void
	{
		_x_scale_factor = (Stage.width / _original_doc_width);
		_y_scale_factor = (Stage.height / _original_doc_height);
		var TitleTextSize = Math.round(36 * _x_scale_factor);  // Originally scaled based on 800x600 flash app
		var PowerMinPeakTextSize = Math.round(50 * _x_scale_factor);
		var PowerNowTextSize = Math.round(104 * _x_scale_factor);
		var TitleTextBuffer = Math.round(10 * _x_scale_factor);
		
		deleteTextMessage();

		// Don't show if the config box is open
		if (_cp_ref == null)
		{
			showText("PowerNowTitle", "Current Usage", TitleTextSize, "center", 10, (Math.round(Stage.height/2)-Math.round(PowerNowTextSize/2)-TitleTextSize), Stage.width-20, TitleTextSize+TitleTextBuffer);
			showText("PowerNow", addThousDelim(_powerNow) + " W", PowerNowTextSize, "center", 10, (Math.round(Stage.height / 2) - Math.round(PowerNowTextSize / 2)), Stage.width - 20, PowerNowTextSize);

			showText("MinTdyTitle", "Today's Low", TitleTextSize, "left", 10, (Stage.height - (TitleTextSize*2) - PowerMinPeakTextSize - 10), Stage.width-20, TitleTextSize+10);
			showText("MinTdy", addThousDelim(_minTdy) + " W", PowerMinPeakTextSize, "left", 10, (Stage.height - TitleTextSize- PowerMinPeakTextSize - 10), Stage.width-20, PowerMinPeakTextSize + 10);
			showText("MinTdyTime", "(" + formatTime(_minTdyHour, _minTdyMin)+")", TitleTextSize, "left", 10, (Stage.height-TitleTextSize-10), Stage.width-20, TitleTextSize);
			
			showText("PeakTdyTitle", "Today's High", TitleTextSize, "left", 10, 10, Stage.width-20,TitleTextSize+10);
			showText("PeakTdy", addThousDelim(_peakTdy) + " W", PowerMinPeakTextSize, "left", 10, (10 + TitleTextSize),Stage.width-20, PowerMinPeakTextSize+10);
			showText("PeakTdyTime", "(" + formatTime(_peakTdyHour, _peakTdyMin)+")", TitleTextSize, "left", 10, (10+TitleTextSize+PowerMinPeakTextSize) , Stage.width-20, TitleTextSize);

			showText("MinMTDTitle", "Monthly Low", TitleTextSize, "right", 10, (Stage.height - (TitleTextSize*2) - PowerMinPeakTextSize - 10), Stage.width - 20, TitleTextSize+10);
			showText("MinMTD", addThousDelim(_minMTD) + " W", PowerMinPeakTextSize, "right", 10, (Stage.height - TitleTextSize- PowerMinPeakTextSize - 10), Stage.width-20, PowerMinPeakTextSize);
			showText("MinMTDTime", "(" + _minMTDMonth + "/"+ _minMTDDay +")", TitleTextSize, "right", 10, (Stage.height-TitleTextSize-10), Stage.width-20, TitleTextSize);
			
			showText("PeakMTDTitle", "Monthly High", TitleTextSize, "right", 10, 10,Stage.width-20,TitleTextSize);
			showText("PeakMTD", addThousDelim(_peakMTD) + " W", PowerMinPeakTextSize, "right", 10, (10 + TitleTextSize),Stage.width-20, PowerMinPeakTextSize);
			showText("PeakMTDTime", "(" + _peakMTDMonth + "/" + _peakMTDDay + ")", TitleTextSize, "right", 10, (10 + TitleTextSize + PowerMinPeakTextSize), Stage.width - 20, TitleTextSize);
		}
	}
	
	//Spit back a formatted number string with commas
	private function addThousDelim(num:Number):String
	{
		// Take the whole number portion and store it as an array of single characters.  
		// This makes it easier to insert the thousands delimiters, as needed. 
		var partOneAr:Array = String(num).split("");  
		
		// Reverse the array so we can process the characters right to left. 
		partOneAr.reverse( );  
		
		// Insert the thousands delimiter after every third character. 
		for (var i = 0, counter = 0; i < partOneAr.length; i++) 
		{ 
			counter++; 
			if (counter > 3) 
			{ 
				counter = 0; 
				partOneAr.splice(i, 0, ","); 
			} 
		}  
		
		// Reverse the array again so that it is back in the original order. 
		partOneAr.reverse( );  
		
		// Create the formatted string using decimalDelim, if necessary. 
		return partOneAr.join(""); 
	}

	//Format time properly
	public static function formatTime(hour:Number, minute:Number):String
	{
		var time:String;
		var adjusthour:Number;
		
		// Subtract 12 if number is bigger than 12
		if (hour > 12)
			adjusthour = hour - 12;
		else
			adjusthour = hour;
		
		// if number is 0, let's make it 12
		if (adjusthour == 0)
			time = "12";
		else if (adjusthour < 10)
			time = "0" + adjusthour;
		else
			time = "" + adjusthour;
			
		// Add zero prepending for minutes < 10
		if (minute < 10)
			time += ":0" + minute;
		else
			time += ":" + minute;
		
		if (hour >= 12)
			time += " pm";
		else
			time += " am";
			
		return time;
	}

	// Create a 'button' for whole screen to trigger config box
	public function createCPButton()
	{
		if (   (_root["cp_btn"] != undefined)
			&& (_root["cp_btn"] != null))
		{
			_root["cp_btn"].removeMovieClip();
		}
			
		// create buttons assuming 800x600 screen initially
		_root.createEmptyMovieClip("cp_btn", _root.getNextHighestDepth());
		_root["cp_btn"].beginFill(0x000000, 0);
		_root["cp_btn"].moveTo(0, 0);
		_root["cp_btn"].lineTo(Stage.width, 0);
		_root["cp_btn"].lineTo(Stage.width, Stage.height);
		_root["cp_btn"].lineTo(0, Stage.height);
		_root["cp_btn"].lineTo(0, 0);
		_root["cp_btn"].endFill();
		_root["cp_btn"]._x = 0;
		_root["cp_btn"]._y = 0;
		
		// Add callback
		_root["cp_btn"].onRelease = Delegate.create(this, this.openCPSettings);
	}
	
	// Display text on screen
	public function showText (myName:String, myText:String, myTextSize:Number, myTextAlign:String, x_pos:Number, y_pos:Number, width:Number, height:Number):Void 
	{
		var tf:TextFormat;
		
		// See if we've defined this field yet
		if (   (_root[myName] != undefined)
			&& (_root[myName] != null))
		{
			_root[myName].t.removeTextField();
			_root[myName].removeMovieClip();
		}
		
		_root.createEmptyMovieClip(myName, _root.getNextHighestDepth());
		_root[myName].createTextField("t", _root.getNextHighestDepth(), x_pos, y_pos, width, height);// , width, height);
		
		createCPButton();

		tf = new TextFormat();
		tf.size = myTextSize;
		tf.color = 0x000000; //black text
		tf.bold = true;
		tf.font = "_sans"; //also _sans _serif and _typewriter available for chumby
		
		_root[myName].t.setNewTextFormat(tf);
		_root[myName].t.wordWrap = false;
		_root[myName].t.type = "static";
		_root[myName].t.autoSize = myTextAlign;
		
		// Update the value
		_root[myName].t.text = myText;
	}
	
	// Open the configuration box
	public function openCPSettings ():Void 
	{
		stopTimer();
		
		// Check if config box already open
		if (_cp_ref != null)
		{
			// Then close without saving
			_cp_ref.closeSettings();
			delete _cp_ref;
			_cp_ref = null;
			startTimer(_refresh_time);
		}

		// Let's make sure the screen is big enough
		else if (  	(Stage.width >= 320)
				 && (Stage.height >= 240))
		{
			// Open up the configuration settings dialog
			_cp_ref = new TedConfig( _app_root, { ted_address:String(_ted_address), refresh_time:String(_refresh_time) }, Delegate.create(this, this.saveCPSettings));
		}
	}
	
	//called from the control panel dialog to save or cancel
	public function saveCPSettings (settings:Object, saveIt:Boolean):Void 
	{
		if (   (saveIt == undefined)
			|| (saveIt == true))
		{
			
			// set items from callback
			_refresh_time = Number(settings.refresh_time);
			_ted_address = String(settings.ted_address);

			//save settings to db
			_savenewsettingsFunc(settings);
			
			// Let's start the process over again
			updateDisplay();
		}

		// Close dialog box
		if (_cp_ref != null)
		{
			_cp_ref.closeSettings();
			delete _cp_ref;
			_cp_ref = null;
		}
		
		// restart the timer to refresh display
		startTimer(_refresh_time);
	}
	
	// Called when timer triggers
	private function timerfunc():Void
	{
		// Let's make sure the timer was not stopped before call
		if (checkTimer)
		{
			getTedXML();
		}
	}
	
	// Determines if timer was already cancelled
	private function checkTimer():Boolean
	{
		if (_myTimer != null)
			return true;
		else
			return false;
	}
	
	// Stops the timer
	private function stopTimer():Void
	{
		if (_myTimer != null)
		{
			clearInterval(_myTimer);
		}
			
		_myTimer = null;
	}
	
	// Starts the timer
	private function startTimer(timerLength:Number):Void
	{
		stopTimer();
		
		if (timerLength == undefined)		
			_myTimer =  setInterval(Delegate.create(this, this.timerfunc), 5000);
		else
			_myTimer =  setInterval(Delegate.create(this, this.timerfunc), timerLength);
			
	}

	// Processes http error responses
	private function getHTTPStatus(httpStatus:Number) : Void
	{
		if(httpStatus < 100) {
			this._httpStatusType = "100";
		}
		else if(httpStatus < 200) {
			this._httpStatusType = "informational";
		}
		else if(httpStatus < 300) {
			this._httpStatusType = "successful";
		}
		else if(httpStatus < 400) {
			this._httpStatusType = "redirection";
		}
		else if(httpStatus < 500) {
			this._httpStatusType = "clientError";
		}
		else if(httpStatus < 600) {
			this._httpStatusType = "serverError";
		}
	}
	
	// Show error messages at bottom of screen
	public function showTextMessage (myText:String, myTextSize:Number):Void 
	{
		// Delete any other previous messages if there
		deleteTextMessage();
		
		_root.createEmptyMovieClip("msg_text_holder", _root.getNextHighestDepth());
		_root.msg_text_holder.createTextField("t", _root.getNextHighestDepth(), 0, Stage.height-Math.round(45 * _y_scale_factor), Stage.width, Math.round(35 * _y_scale_factor));
		
		var tf:TextFormat = new TextFormat();
		tf.size = myTextSize*_x_scale_factor;
		tf.align = "center";
		tf.color = 0xFF0000; //red text
				
		tf.bold = true;
		tf.font = "_sans"; //also _serif and _typewriter available for chumby

		_root.msg_text_holder.t.setNewTextFormat(tf);
		_root.msg_text_holder.t.text = myText;											
		_root.msg_text_holder.t.wordWrap = true;
		delete tf;
	}
	
	// Delete error messages at bottom of screen
	private function deleteTextMessage ():Void
	{
		if (_root.msg_text_holder)
		{
			_root.msg_text_holder.t.removeTextField();
			_root.msg_text_holder.removeMovieClip();
		}
	}
	
}